/*
 * Copyright 2012 Gayan Perera
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
package gap.maven.script.components.api;

import java.io.File;
import java.util.zip.ZipEntry;

/**
 * This class defines the pattern which can be used when extracting some
 * selected files from an archive. The path and file name can be given
 * as a pattern using method chaining.
 * 
 * @author gayan
 */
public final class ExtractorPattern {
    public enum NameOperators {
        STARTS_WITH, ENDS_WITH, CONTAINS, EQUAL, REGEX
    };

    private String path = null;
    private String fileName;
    private NameOperators operator;

    /**
     * Creates a new instance of ExtractorPattern which will act as an whild card.
     */
    public ExtractorPattern() {
    }
    
    /**
     * The path to be matched. This will check if a given file is in the specified path.
     * @param path The file path which should not contain the file name and this cannot be null or empty.
     * @return The current modified instance of the pattern.
     */
    public ExtractorPattern setPath(String path) {
        if(path.endsWith(File.separator)) {
            this.path = path.substring(0, path.length() - 1);
        } else {
            this.path = path;
        }
        
        return this;
    }

    /**
     * The file name to be matched. The file name can be given as regex, starts with, ends with, contains, equal.
     * @param name The file name which cannot be null or empty. This can be a regex string if the matching operator is
     * {@link NameOperators#REGEX}.
     *  
     * @param operator one of {@link NameOperators}.
     * @return The current modified instance of the pattern.
     */
    public ExtractorPattern setFileName(String name, NameOperators operator) {
        this.fileName = name;
        this.operator = operator;
        return this;
    }

    /**
     * The file name to be matched using the EQUAL operator.
     * @param fileName The file name which cannot be null or empty.
     * @return The current modified instance of the pattern.
     */
    public ExtractorPattern setFileName(String fileName) {
        setFileName(fileName, NameOperators.EQUAL);
        return this;
    }

    /**
     * Checks if the given {@link ZipEntry} matches this file pattern. Both the name and path condition must match to
     * return <code>true</code>.
     * @param entry zip file entry to match with this pattern which cannot be null.
     * @return <code>true</code> if both the filename and path conditions returns true.
     */
    public boolean match(ZipEntry entry) {
        boolean nameMatched = true;
        boolean pathMatched = true;

        final String name = entry.getName();
        final String fpath = name.substring(0, name.lastIndexOf(File.separator));
        final String fname = name.substring(name.lastIndexOf(File.separator) + 1);
        
        // only one condition can be false at a given time which are connected by OR. 
        if(fileName != null) {
            switch (operator) {
                case CONTAINS: {
                    nameMatched = fname.contains(fileName);
                    break;
                }

                case STARTS_WITH: {
                    nameMatched = fname.startsWith(fileName);
                    break;
                }
                case ENDS_WITH: {
                    nameMatched = fname.endsWith(fileName);
                    break;
                }
                case EQUAL: {
                    nameMatched = fname.equals(fileName);
                    break;
                }
                case REGEX: {
                    nameMatched = fname.matches(fileName);
                    break;
                }
            }            
        }

        if ((path != null) && !path.equals(fpath)) {
            pathMatched = false;
        }

        return (nameMatched && pathMatched);
    }
}
